Contents
MQ: Message Queues for Windows NT [Unregistered Version]

 MQ is a product of TENTACLE SYSTEMS
"Software from the Sign of the Squid"
Copyright  1992-1994 Steven G. Judd All Rights Reserved

Introduction

License Information

Differences between Registered and Unregistered versions

How to...

Obtain the Registered Version

Obtain support

Include MQ in your applicaton.

Link with MQ

Obtain error message text

Basic API...

MqCreate	Creates a new queue
MqAttach	Attaches an existing queue
MqDetach	Detaches an existing queue
MqDestroy	Marks a queue for delete
MqPut	Puts a message in a queue
MqGet	Gets a message from a queue
MqCancelGet	Cancels a blocking GET operation
MqCancelPut	Cancels  a blocking PUT operation

Management API...

MqGetGlobalInfo	Obtain information about the global state of the queuing system
MqGetQInfo	Obtain information about a particular queue
MqEnumQ	Obtain the names of all currently-defined queues

Example Program


Introduction

MQ provides a high-performance Interprocess Communications (IPC) mechanism similar to the message queue facility found on UNIX  System V and available on most other UNIX systems.

MQ offers significant enhancements to the UNIX message queue facility:

All queues are named, and can be directly attached by name;

message type is a separate parameter and need not appear in the body of the message;

a timeout value can be provided on both PUT and GET operations;

blocking PUT and GET operations can be cancelled;

API calls are provided to extract information on the global state of the queuing system and on individual queues;

structured exception handling is used to identify invalid parameters and return an error to the caller.

MQ differs from the standard Windows NT IPC mechanisms (Mailslots,  Named Pipes and Sockets) in the following ways:

Multiple concurrent readers:  an MQ message queue can be attached and read concurrently by an unlimited number of threads (which may exist in an unlimited number of processes).  A Named Pipe or Mailslot can be read by a thread  within the process that created it, and no-one else.     A Socket may be "handed off" among processes, but can be read by exactly one process at a time.

Multiple concurrent writers: an MQ message queue can be attached and written concurrenly by an unlimited number of threads (which may exist in an unlimited number of processes). A Named Pipe may be shared serially (one writer at a time).  Mailslots offer write sharing similar MQ message queues.  Sockets do not offer write-sharing.

Filtering:  all messages enqueued to MQ message queues have a 32-bit user-specified type associated with them.  Dequeue operations can specify the type of message desired;  only messages of the speciffied type will be dequeued (a type value of 0 (zero)) indicates that any type is acceptable).  Mailslots, Named Pipes, and Sockets do not offer any form of filtering

Performance:  MQ is 2.8 times faster than Mailslots for short messages (< 100 bytes) and 2 times faster for messages of 16k bytes.  (Performance tests were done on a 486/33 with 64KB Cache)

Queue Life Cycle


Including MQ in your Application

API prototypes, structure defnitions, and constants are defined in the include file MQ_PUB.H.  Symbols for error codes are defined in MQ_ERR.H.  'C' programs can include these files directly.

C++ programs should indentify MQ_PUB.H and MQ_ERR.H as  'C' include files as follows:

extern "C" {
#include <mq_pub.h>
#include <mq_err.h>
}

'C' and C++ programs should be compiled with multi-threading support to take full advantage of MQ's multi-threading features.  Consult your compiler documentation for details on enabling multi-threading support.


Linking with MQ

Link your application with MQ.LIB to resolve references to MQ API routines.  MQ.DLL and MSVCRT10.DLL must be available to your application at run time.


MqCreate

long MqCreate(lpHMQ,   lpszName)

MqCreate creates the new queue named by lpszName and returns the handle pointed to by lpHMQ.

Parameter	Description
lpHMQ	address of a Queue Handle (HMQ) that will be used for operations on the newly created queue
lpszName	address of a zero-terminated string containing the name of the queue to be created.  Names have a maximum length of 255.  Note that names are case sensitive.
Return Value	Description
MQ_SUCCESS	The queue was created.
MQ_BADHADDRESS	The address of the Queue Handle is invalid
MQ_BADNAME	The address of the name is invalid
MQ_EXISTS	The queue already exists
MQ_NOMEMORY	Insufficient free memory was available to create a new Queue Handle
MQ_FAILED	The create operation was unsuccessful because a Win32 system service failed.
MqAttach


MqAttach

long MqAttach(lpHMQ,   lpszName)

MqAttach attaches the existing queue named by lpszName and returns the handle pointed to by lpHMQ.

Parameter	Description
lpHMQ	address of a Queue Handle (HMQ) that will be used for operations on the newly created queue
lpszName	address of a zero-terminated string containing the name of the queue to be cattached.  Names have a maximum length of 255.  Note that names are case sensitive.
Return Value	Description
MQ_SUCCESS	The queue was attacheded.
MQ_BADHADDRESS	The address of the Queue Handle is invalid
MQ_BADNAME	The address of the name is invalid
MQ_ALREADYATTACHED	The handle pointed to by lpHMQ appears to be a valid handle for an already-attached queue.  This is commonly caused by passing an uninitialized stack variable for HMQ.
MQ_NOSUCHQ	The queue does not exist
MQ_NOMEMORY	Insufficient free memory was available to create a new Queue Handle
MQ_FAILED	The attach operation was unsuccessful because a Win32 system service failed.
MqDetach


MqDetach

long MqDetach(HMQ)

MqDetach detaches the queue represented by HMQ.  If the queue was previously marked for removal from the system by a call to MqDestroy, and the reference count for the queue is reduced to zero by the detach operation, the queue is destroyed.

Parameter	Description
HMQ	A Queue Handle (HMQ) returned by MqCreate or MqAttach
Return Value	Description
MQ_DETACHED	The queue was detached.
MQ_DESTROYED	The queue was previously marked for removal from the system, and the current thread detach operation reduced the reference count for the queue to zero: the queue was destroyed.
MQ_BADHANDLE	The address value in  the Queue Handle is invalid
MQ_NOTATTACHED	The handle appears valid, but is not the handle of a currently attached queue.
MQ_NOTOWNER	The handle  appears valid, but is not the  handle for a queue attached by the calling thread.
MqDestroy


MqDestroy

long MqDestroy(HMQ)

MqDestroy marks the queue represented by HMQ for removal from the system, and detaches it.  If the reference count for the queue is reduced to zero by the detach operation, the queue is destroyed immediately.

Parameter	Description
HMQ	A Queue Handle (HMQ) returned by MqCreate or MqAttach
Return Value	Description
MQ_DETACHED	The queue was marked for removal and detached.
MQ_DESTROYED	The current thread detach operation reduced the reference count for the queue to zero: the queue was destroyed.
MQ_BADHANDLE	The address value in  the Queue Handle is invalid
MQ_NOTATTACHED	The handle appears valid, but is not the handle of a currently attached queue.
MQ_NOTOWNER	The handle  appears valid, but is not the  handle for a queue attached by the calling thread.
MqPut


MqPut

long MqPut(HMQ, lpMsg, lMsgsize, lType, bBlock, ulTimeout)

MqPut inserts the message pointed to by lpMsg into the queue represented by HMQ. The type value provided in lType is assigned to the message.

Parameter	Description
HMQ	A Queue Handle (HMQ) returned by MqCreate or MqAttach
lpMsg	Address of the message to be enqueued. Declared as a char * in mq_pub.h
lMsgsize	long value indicating the size of the mesasge to be enqueued
lType	long value indicating the user-defined type to be assigned to the message
bBlock	Boolean value indicating whether or not this operation is allowed to block.  Valid values are   MQ_BLOCKING or MQ_NONBLOCKING
ulTimeout	Unsigned long timeout value.  If bBlock is MQ_BLOCKING, the time in milliseconds that the calling thread will wait before abandoning the operation.  If a value of INFINITE is provided, the calling thread will not time out.
Return Value	Description
MQ_SUCCESS	The message was enqueued
MQ_PUTWOULDBLOCK	The enqueue operation would block waiting for sufficient resources, and bBlock specified MQ_BLOCKING
MQ_TIMEOUT	The enqueue operation was blocked waiting for sufficient resources, and bBlock specified MQ_BLOCKING,
MQ_PUTCANCELLED	The enqueue operation was blocked waiting for sufficient resources, and bBlock specified MQ_BLOCKING,
MQ_BADHANDLE	The address value in  the Queue Handle is invalid
MQ_NOTATTACHED	The handle appears valid, but is not the handle of a currently attached queue.
MQ_NOTOWNER	The handle  appears valid, but is not the  handle for a queue attached by the calling thread.
MQ_BADBLOCKPARAM	The value supplied for bBlock was not MQ_BLOCKING or MQ_NONBLOCKING
MQ_BADBUFADDRESS	The address of the message is invalid
MQ_JUSTTOOBIG	The message exceeds the system maximum permitted length
MqGet


MqGet

long MqGet(HMQ, lType, lpTypeRead, lpBuf, lBufsize,lpBytesRead, bBlock, ulTimeout)

MqGet dequeues a  message of type lType into the buffer pointed to by lpBuf.

Parameter	Description
HMQ	A Queue Handle (HMQ) returned by MqCreate or MqAttach
lType	long Filter value;  only messages of type lType will be dequeued.  If lType has a value of MQ_TYPE_ANYmessages of all types are accepted
lpTypeRead	Address of a long variable to receive the type of the message read.
lpBuf	Address of the buffer to receive the message dequeued. Declared as a char * in mq_pub.h
lBufsize	long value indicating the size of the buffer pointed to by lpBuf
lpBytesRead	address of a long value indicating the actual number of bytes read
bBlock	Boolean value indicating whether or not this operation is allowed to block.  Valid values are   MQ_BLOCKING or MQ_NONBLOCKING
ulTimeout	Unsigned long timeout value.  If bBlock is MQ_BLOCKING, the time in milliseconds that the calling thread will wait before abandoning the operation.  If a value of INFINITE is provided, the calling thread will not time out.
Return Value	Description
MQ_SUCCESS	A message was dequeued
MQ_TRUNC	A message was dequeued, but the buffer provided was too small.  lBufsize bytes are returned in the buffer.
MQ_GETWOULDBLOCK	The dequeue operation would block waiting for a message, and bBlock specified MQ_BLOCKING
MQ_TIMEOUT	The dequeue operation was blocked waiting for a message, and bBlock specified MQ_BLOCKING,
MQ_GETCANCELLED	The dequeue operation was blocked waiting for a message, and bBlock specified MQ_BLOCKING,
MQ_BADHANDLE	The address value in  the Queue Handle is invalid
MQ_NOTATTACHED	The handle appears valid, but is not the handle of a currently attached queue.
MQ_NOTOWNER	The handle  appears valid, but is not the  handle for a queue attached by the calling thread.
MQ_BADBLOCKPARAM	The value supplied for bBlock was not MQ_BLOCKING or MQ_NONBLOCKING
MQ_BADBUFADDRESS	The address passed as lpBuf is invalid
MQ_BADLENADDRESS	The address passed as lpBytesRead is invalid
MQ_BADTYPEADDRESS	The address passed as lpTypeRead is invalid.
MqCancelGet


MqCancelGet

long MqCancelGet(HMQ)

MqCancelGet unconditionally cancels a blocking get operation being performed by another thread in the calling process on the queue represented by HMQ.  If MqCancelGet is called when no blocking operation is in progress, the call completes successfully but has no effect.

Parameter	Description
HMQ	A Queue Handle (HMQ) returned by MqCreate or MqAttach
Return Value	Description
MQ_SUCCESS	The cancel operation was successful.
MQ_BADHANDLE	The address value in the Queue Handle is invalid
MQ_NOTATTACHED	The handle appears valid, but is not the handle of a currently attached queue.
MqCancelPut


MqCancelPut

long MqCancelPut(HMQ)

MqCancelPut unconditionally cancels a blocking put operation being performed by another thread in the calling process on the queue represented by HMQ.  If MqCancelPut is called when no blocking operation is in progress, the call completes successfully but has no effect.

Parameter	Description
HMQ	A Queue Handle (HMQ) returned by MqCreate or MqAttach
Return Value	Description
MQ_SUCCESS	The cancel operation was successful.
MQ_BADHANDLE	The address value in the Queue Handle is invalid
MQ_NOTATTACHED	The handle appears valid, but is not the handle of a currently attached queue.
MqGetGlobalInfo


MqGetGlobalInfo

long MqGetGlobalInfo(lpGlobalInfo)

MqGetGlobalIinfo fills in the provided MqGlobalInfo structure with information on the global state of the queuing system.  Note that MqGetGlobalInfo locks critical MQ data structures while executing:  Frequent calls to MqGetGlobalInfo can negatively affect performance.

Parameter	Description
lpGlobalInfo	Address of an MqGlobalInfo structure
Return Value	Description
MQ_SUCCESS	Global information was successfully returned
MQ_BADGLOBALINFO	The address passed as lpGlobalInfo is invalid
MqGetQInfo


MqGetQInfo

long MqGetQInfo(HMQ, lpQueueInfo)

MqGetQIinfo fills in the provided MqQueueInfo structure with information on the state of the queue represented by HMQ.  Note that MqGetQInfo locks critical MQ data structures for the queue while executing:  Frequent calls to MqGetQInfo can negatively affect performance for the queues on which it is reporting.

Parameter	Description
HMQ	A Queue Handle (HMQ) returned by MqCreate or MqAttach
lpQueueInfo	Address of an MqQueueInfo structure
Return Value	Description
MQ_SUCCESS	Queue information was successfully returned
MQ_BADHANDLE	The address value in the Queue Handle is invalid
MQ_NOTATTACHED	The handle appears valid, but is not the handle of a currently attached queue.
MQ_BADQUEUEINFO	The address passed as lpQueueInfo is invalid
MqEnumQ


MqEnumQ

long MqEnumQ(void EnumCallback(char *))

MqEnumQ iteratively calls the user provided callback routine with the name of each queue currently defined.  The user-provided routine must bedefined as void, e.g returning no status value and must take a pointer to a null-terminated string as it's single input parameter.

Parameter	Description
EnumCallback	Address of a user-provided routine to be called by MqEnumQ with the name of each queue in the system.
Return Value	Description
MQ_SUCCESS	Queue names were  successfully passed to the user-provided callback
MQ_BADCALLBACK	The address of the user-provided callback routine is invalid


Obtaining the Registered version of MQ

This is not free software.  This license allows you to use this software for evaluation purposes without charge for a period of 28 days.  If you use this software after the 28 day evaluation period a registration fee of $39 is required.  Payments must be in US dollars drawn on a US bank, made payable to Steven G. Judd, and should be sent to

Steven G. Judd
Tentacle Systems
84 Cove Road, Haddam Neck
East Hampton, CT.    06424

Credit card ordering and quantity discounts are available, as described below and in the file ORDER.TXT.  When payment is received you will be sent a registered copy of the latest version of MQ.

WHY REGISTER?

First, registration provides you with a license to use this software.  Using the unregistered version beyond the evaluation period constitutes a violation of the copyright laws of the United States of America.  In addition, the registered version offers greater system capacity in terms of message size, number of messages, and number of queues.  See the differences section for details.

MQ Price List

MQ is issued in both development and run-time forms.  The development form includes the API help file and link library, the run-time version includes only the .DLL file.  A single development license includes a Run-time license.

Development Edition

Quantity	Price Each
1	$39.00
2-9	$35.00
10-24	$31.00
25-49	$27.00
50-99	$23.00
100-199	$19.00
200-499	$15.00
500 and Up	$10.00

Additional Run-time licenses:

Quantity	Price Each
1-99	$10.00
100-499	$7.00
500 and Up	$4.00


License Information

MQ Version 1.0 (Unregistered Version)
Copyright  1992-1994 Steven G. Judd
All Rights Reserved

For ordering information, see "Obtaining the Registered Version of MQ" or the file ORDER.TXT.

License Agreement

You should carefully read the following terms and conditions before using this software.

Shareware Version

You are hereby licensed to:  use the Shareware Version of the software for a 28 day evaluation period; make as many copies of the Shareware version of this software and documentation as you wish; give exact copies of the original Shareware version to anyone; and distribute the Shareware version of the software and documentation in its unmodified form via electronic means.  There is no charge for any of the above.

You are specifically prohibited from charging, or requesting donations, for any such copies, however made; and from distributing the software and/or documentation with other products (commercial or otherwise) without prior written permission, with one exception:  Disk Vendors approved by the Association of Shareware Professionals are permitted to redistribute MQ, subject to the conditions in this license, without specific written permission.

Unregistered use of MQ after the 28-day evaluation period is in violation of federal copyright laws.

Evaluation and Registration

One registered copy of MQ may either be used by a single person who uses the software personally on one or more computers,or installed on a single workstation used nonsimultaneously by multiple people, but not both.

You may access the registered version of MQ through a network, provided that you have obtained individual licenses for the software covering all workstations that will access the software through the network.

REDISTRIBUTION

Applications that use the MQ API require the presence of MQ.DLL to execute.  Redistribution of MQ.DLL requires a run-time license for each target system or separately negotiated restribution agreement.

Governing Law

This agreement shall be governed by the laws of the State of Connecticut.

Disclaimer of Warranty

THIS SOFTWARE AND THE ACCOMPANYING FILES ARE SOLD "AS IS" AND WITHOUT WARRANTIES AS TO PERFORMANCE OF MERCHANTABILITY OR ANY OTHER WARRANTIES WHETHER EXPRESSED OR IMPLIED.  Because of the various hardware and software environments into which MQ may be put, NO WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE IS OFFERED.

Good data processing procedure dictates that any program be thoroughly tested with non-critical data before relying on it.

The user must assume the entire risk of using the program.  ANY LIABILITY OF THE SELLER WILL BE LIMITED EXCLUSIVELY TO PRODUCT REPLACEMENT OR REFUND OF PURCHASE PRICE.


How to get Support

Support is available by sending electronic mail to CompuServe Account 71762,3712.  You can also send mail via the Internet to 71762.3712@compuserve.com.

Questions, suggestions, applause, brickbats, etc. are welcome.  Please keep questions as specific as possible, and use the phrase "MQ SUPPORT", "MQ SUGGESTION"  etc. in the title of the message.


Differences between the Shareware and Registered versions

The unregistered shareware version of MQ is fully functional;  it contains no "time bombs", "guilt messages", or other obnoxious limitations.  The shareware version has less capacity than the registered version in terms of the size and number of messages that can be held in queue, and the number of queues that can be defined.  The intent of the author is to provide a platform upon which serious applications can be developed.

Deployment in a production environment (or use beyond the evaluation period) requires the purchase of a license, in return for which a higher-capacity version will be provided.  The registered version provides sufficient resources to support very large system configurations.   Note that only storage that is actually used for messages will ever be referenced, so that the larger capacity of the registered version does not impose any resource or performance penalty over the shareware version.

Run-time licenses are available at a nominal fee, allowing the use of MQ on systems that do not require development capability (see Obtaining the Registered Version of MQ).

MQ SYSTEM LIMITS

RESOURCE	SHAREWARE LIMIT	REGISTERED LIMIT
Maximum number of Queues	32	1024
Maximum number of Messages	256	8192
Maximum Message Size (bytes)	16384	1048576
Number of 512-byte Message Segments	4096	16384
Total Queue capacity (bytes)	2097152	8388608


Queue Life Cycle

A queue is created when an application issues the MqCreate API call.  The queue remains in existence  until:

the queue is marked for removal from the system by an MqDestroy API call -and -

the reference count for the queue drops to zero (meaning all clients have detached) -or -

all clients have detached from MQ and the DLL is unloaded by Windows NT.

Message placed in a queue remain until they are dequeued or the queue is destroyed.

Applications that require queues to remain in existence even when no application clients are using MQ must provide a "dummy" application client that creates at least one queue and keeps it attached.  This prevents the DLL from being unloaded.  A future version of MQ will offer the option of running as a Windows NT Service, eliminating the need for such a "dummy" client.

Implicit Detach

MQ is both thread-safe and thread-aware: when a client thread exits, all MQ queues attached by that thread are automatically detached.

Thread Support


Thread Support

All queue operations in MQ are performed on a Queue Handle.  Handles are created by MqCreate and MqAttach.  A handle is associated with the thread that created it, and cannot be used by another thread for MqGet and MqPut operations.  All currently-attached handles for a given thread are automatically detached when the thread in question terminates.


Queue Handle

HMQ  hMq

Declared as a void * in mq_pub.h, a Queue Handle is created for the calling thread by calling MqAttach or MqCreate, and represents the named queue upon which MQ operations are to be performed.


MQ_BLOCKING
MQ_BLOCKING	0x00000001	defined in mq_pub.h

Indicates that the operation is allowed to block the calling thread if necessary.


MQ_NONBLOCKING
MQ_NONBLOCKING	0x00000000	defined in mq_pub.h

Indicates that the operation is NOT allowed to block the calling thread.


INFINITE
INFINITE	0xFFFFFFFF	Win32 constant.


MQ_TYPE_ANY
MQ_TYPE_ANY	0x00000000	defined in mq_pub.h


MqGlobalInfo

Structure type defined in mq_pub.h containing:

long max_q	total number of queues that can be defined
long max_msg	number of message headers
long max_msg_size	system maximum message size
long max_seg	number of message segments
long seg_size	size of a message segment
long free_msg	number of free message headers
long free_seg	number of free message segments
long free_q	number of free queues
long wait_msg_count	number of clients blocked for a free message header
long wait_seg_count	number of clients blocked for a free message segment


MqQueueInfo

Structure type defined in mq_pub.h containing:

long attach_count	number of theads that have this queue attached
long msg_count	number of messages in the queue
long wait_count	number of threads blocked waiting for a message
BOOL destroy	non-zero if queue has been marked for removal
char name[255]	name of this queue


Extracting Error Message Text

The error codes returned by MQ operations were generated by the Windows NT Message Compiler.  The text strings assocoated with each error code are imbedded in MQ.DLL, and can be obtained by calling the Windows NT FormatMessage procedure.

Only English text is available at this time.

Example

void format_message(long msgid)

{

char  cBuffer[256];
DWORD dwStatus;

dwStatus = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle("mq.dll"), msgid,
MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
cBuffer,sizeof(cBuffer), NULL);

if (dwStatus > 0)

printf("%s\n",cBuffer);

else

printf("Error:%d\n",GetLastError());

}


Example Program

A simple example program, MQEXAMPL.C, and makefile, MQEXAMPL.MAK, are provided in the MQ distribution.  MQEXAMPLE.C provides an example of every MQ API call.

Rebuilding the executable using NMAKE as follows:

nmake  MQ=<mqpath> -f MQEXAMPL..MAK

where <mqpath> is the device and directory path where MQ is installed.  For example, if MQ is installed in C:\MQ, the nmake command will look like this:

nmake MQ=C:\MQ -f MQEXAMPL.MAK